"""
Copyright 2012 Wieser Dietmar, Margit Mutschlechner.

This file is part of Multimedia Social Networking Platform.

Multimedia Social Networking Platform is free software: 
you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

Multimedia Social Networking Platform is distributed
in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with Multimedia Social Networking Platform.  
If not, see <http://www.gnu.org/licenses/>.

"""

from PyQt4 import QtCore
from PyQt4 import QtGui
from msnp.gui import UIText, Resources, GUIHelper, MyStyle
from msnp.service.utils import DateFormatter
from msnp.model import PTPModel
from msnp.service.network import NetworkController
from msnp.persistence import PersistenceController, XMLController
from msnp import gui

class PersonalMessageWidget(QtGui.QWidget):
    """This class contains the personal message widget to display messages exchanged between users.
    
    Parameters:
        __parent: A QWidget object containing the parent frame. Default None.
        __mainLayout: A QVBoxLayout object containing the items __chatHistory, __hline and __chatEditWidget.
        __chatHistory: A ChatHistoryWidget object containing the items __chatPartnerName and __chatMessages.
        __chatPartnerName: A QLabel object.
        __chatMessages: A list of ChatMessage objects.
        __hline: A QFrame object containing a horizontal line.
        __chatEditWidget: A QWidget item containing the elements __txtChat and __butSend.
        __txtChat: A QLineEdit object.
        __butSend: A QPushButton object connected to the method send().
    """
    def __init__(self, chatPartnerName, chatMessages, parent=None):
        """The init-method."""
        QtGui.QWidget.__init__(self, parent)
        self.__chatPartnerName = chatPartnerName
        self.__chatMessages = chatMessages
        self.setWindowTitle(UIText.TITLE_CHAT_WITH + " " + chatPartnerName)
        self.setWindowIcon(QtGui.QIcon(Resources.IMAGE_CHAT_ICON))
        self.setFixedSize(400, 600)
        self.__mainLayout = QtGui.QVBoxLayout()
        self.__build()
        self.setLayout(self.__mainLayout)
        GUIHelper.centerWidget(self)
        
    def __build(self):
        """Initializes the items contained in the widget."""
#        self.__initLabels()
        self.__initTextEdit()
        self.__initButton()
        self.__initChatEditWidget()
        self.__initChatHistory()
        self.__initHLine()
        self.__mainLayout.addWidget(self.__chatHistory)
        self.__mainLayout.addWidget(self.__hline)
        self.__mainLayout.addWidget(self.__chatEditWidget)
        
    def __initChatHistory(self):
        """Initializes the item __chatHistory."""
        self.__chatHistory = ChatHistoryWidget(self.__chatPartnerName, self.__chatMessages)
        
    def __initChatEditWidget(self):
        """Initializes the item __chatEditWidget."""
        layout = QtGui.QVBoxLayout()
        self.__chatEditWidget = QtGui.QWidget()
        layout.addWidget(self.__txtChat)
        layout.addWidget(self.__butSend)
        self.__chatEditWidget.setLayout(layout)
        self.__chatEditWidget.setFixedHeight(150)
        
    def __initTextEdit(self):
        """Initializes the item __txtChat."""
        self.__txtChat = QtGui.QTextEdit()
        self.__txtChat.setEnabled(True)
        
    def __initButton(self):
        """Initializes the item __butSend."""
        self.__butSend = QtGui.QPushButton(UIText.BUT_SEND, self)
        self.__butSend.setFocusPolicy(QtCore.Qt.NoFocus)
        self.__butSend.setIcon(QtGui.QIcon(Resources.IMAGE_BUT_SEND))
        self.connect(self.__butSend, QtCore.SIGNAL('clicked()'), self.__send)
    
    def __initHLine(self):
        """Initializes the item __hline."""
        self.__hline = QtGui.QFrame()
        self.__hline.setLineWidth(2)
        self.__hline.setFrameShape(QtGui.QFrame.HLine)
        
    def closeEvent(self, event):
        """This method is called when the widget is closing."""
        gui.GUIController.closePersonalMessageWidget(self.__chatPartnerName)
        event.accept()
        
    def __send(self):
        """This method is connected to the QPushButton object __butSend."""
        text = unicode(str(self.__txtChat.toPlainText()))
        if text != None and len(text) > 0:
            withoutWhitespaces = text.expandtabs().replace(" ", "")
            if len(withoutWhitespaces) > 0:
                NetworkController.sendPersonalMessage(self.__chatPartnerName, text)
                self.changeHappened()
                self.__txtChat.setText("")
        
    def changeHappened(self):
        """If a change in the chat history happened this method notifies the item __chatHistory."""
        self.__chatHistory.changeHappened()
        
        
class ChatHistoryWidget(QtGui.QFrame):
    """This class contains a chat history frame, which is the main center part of the personal message widget.
    
    Parameters:
        __parent: A QWidget object containing the parent frame. Default None.
        __mainLayout: A QVBoxLayout object containing all object of this widget.
        __chatPartnerName: A String containing the name of the chat partner.
        __chatMessages: A list of ChatMessage objects.
        __settings: A Settings object containing the stores settings.
        __scrollArea: A QScrollArea object containing the item __messageLayout.
        __messagesLayout: A QWidget object containing various SingleMessageWidget objects.
    """
    def __init__(self, chatPartnerName, chatMessages, parent=None):
        """The init-method."""
        QtGui.QWidget.__init__(self, parent)
        self.__chatPartnerName = chatPartnerName
        self.__chatMessages = chatMessages
        self.__settings = XMLController.readAllSettings()
        self.__build()
        
    def __build(self):
        """Initializes the widget and its contained items."""
        self.__cleanLayout()
        self.__scrollArea = QtGui.QScrollArea()
        self.__messagesLayout = QtGui.QVBoxLayout()
        messagesWidget = QtGui.QWidget()
        if self.__chatMessages != None and len(self.__chatMessages) > 0:
            #sorting by timestamp
            self.__chatMessages = PTPModel.ChatMessage.sortChatMessages(self.__chatMessages)
            lastSendername = ""
            thisSendername = ""
            for chatMessage in self.__chatMessages:
                thisSendername = chatMessage.getSendername()
                displaySendername = lastSendername != thisSendername
                lastSendername = thisSendername
                self.__addMessageWidget(chatMessage, displaySendername)
        messagesWidget.setLayout(self.__messagesLayout)
        self.__scrollArea.setFrameShape(QtGui.QFrame.StyledPanel)
        self.__scrollArea.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
        self.__mainLayout.addWidget(self.__scrollArea)
        self.__scrollArea.setWidget(messagesWidget)
        QtCore.QCoreApplication.processEvents()
        self.__scrollArea.verticalScrollBar().setValue(self.__scrollArea.verticalScrollBar().maximum())
            
            
    def __cleanLayout(self):
        """Removes all items from the item __mainLayout."""
        import sip
        if self.layout() != None:
            oldLayout = self.layout()
            for i in reversed(range(oldLayout.count())):
                oldLayout.itemAt(i).widget().setParent(None)
            sip.delete(oldLayout)
        self.__mainLayout = QtGui.QVBoxLayout()
        self.setLayout(self.__mainLayout)
        
    def __addMessageWidget(self, chatMessage, displaySendername):
        """Adds a SingleMessageWidget object with the given message and username to the item __messagesLayout."""
        if displaySendername:
            hline = QtGui.QFrame()
            hline.setFrameShape(QtGui.QFrame.HLine)
            self.__messagesLayout.addWidget(hline)
        mWidget = SingleMessageWidget(chatMessage, displaySendername)
        self.__messagesLayout.addWidget(mWidget)
        
    def changeHappened(self):
        """This method is called when a change in the chat messages happened. The messages are read again and the widget is build newly."""
        username = self.__settings.getCurrentUserSettings().getUsername()
        self.__chatMessages = PersistenceController.selectChatHistoryByPartnernameAndUsername(self.__chatPartnerName, username)
        self.__build()

        
class SingleMessageWidget(QtGui.QWidget):
    """This class contains a single message displayed inside a ChatHistoryWidget object.
    
    Parameters:
        __parent: A QWidget object containing the parent frame. Default None.
        __mainLayout: A QVBoxLayout object containing the items __lineWidget and __lblText.
        __displaySendername: A boolean value, True if the sender name should be displayed, False otherwise.
        __chatMessage: A ChatMessage object.
        __settings: A Settings object containing the stores settings.
        __lblText: A QLabel object.
        __lineWidget: A QWidget object containing the items __lblStatus and __lblTime.
        __lblStatus: A QLabel object.
        __lblTime: A QLabel object.
        __lblSender: A QLabel object.
    """
    def __init__(self, chatMessage, displaySendername, parent=None):
        """The init-method."""
        QtGui.QFrame.__init__(self, parent)
        self.__chatMessage = chatMessage
        self.__displaySendername = displaySendername
        self.__mainLayout = QtGui.QVBoxLayout()
        self.__build()
        self.setLayout(self.__mainLayout)
        
    def __build(self):
        """Initializes the widget and its contained items."""
        self.__initLabels()
        self.__initLineWidget()
        if self.__displaySendername:
            self.__mainLayout.addWidget(self.__lblSender)
        self.__mainLayout.addWidget(self.__lineWidget)
        self.__mainLayout.addWidget(self.__lblText)
        
    def __initLineWidget(self):
        """Initializes the item __lineWidget and adds its contained items."""
        layout = QtGui.QHBoxLayout()
        self.__lineWidget = QtGui.QWidget()
        layout.addWidget(self.__lblStatus)
        layout.addWidget(self.__lblTime)
        self.__lineWidget.setLayout(layout)
        
    def __initLabels(self):
        """Initializes the QLabel objects __lblSender, __lblStatus, __lblTime and __lblText."""
        if self.__displaySendername:
            self.__lblSender = QtGui.QLabel(self.__chatMessage.getSendername())
            self.__lblSender.setFont(MyStyle.getFont15Bold())
            self.__lblSender.setAlignment(QtCore.Qt.AlignCenter)
        
        timeString = DateFormatter.formatTimeWithDay(self.__chatMessage.getLocaltime())
        self.__lblTime = QtGui.QLabel(timeString)
        self.__lblTime.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignTop)
        self.__lblTime.setFont(MyStyle.getFont8())
        
        status = self.__chatMessage.getStatus()
        self.__lblStatus = QtGui.QLabel(GUIHelper.chatStatusToString(status))
        self.__lblStatus.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignTop)
        self.__lblStatus.setFont(MyStyle.getFont8())
        palette = self.__lblStatus.palette()
        if status == PTPModel.ChatMessageStatus.SENDING:
            palette.setColor(self.__lblStatus.foregroundRole(), QtCore.Qt.darkYellow)
        elif status == PTPModel.ChatMessageStatus.SENT:
            palette.setColor(self.__lblStatus.foregroundRole(), QtCore.Qt.darkGreen)
        else:
            palette.setColor(self.__lblStatus.foregroundRole(), QtCore.Qt.darkRed)
        self.__lblStatus.setPalette(palette)
        
        self.__lblText = QtGui.QLabel()#18
        message = GUIHelper.splitLongWords(self.__chatMessage.getMessage())
        self.__lblText.setText(message)
        self.__lblText.setWordWrap(True)
        self.__lblText.setFont(MyStyle.getFont13Courier())
        self.__lblText.setMinimumWidth(320)
